package orbit

import (
	"errors"
	"fmt"
	"sync"

	"gddgame.cc/galaxy/binocle"
	. "gddgame.cc/galaxy/common/dsl/db"
	"gddgame.cc/galaxy/utils/cache"
	"gddgame.cc/galaxy/utils/def"
	"gddgame.cc/galaxy/utils/orm"
)

type Environment struct {
	id      string
	context def.Context
	service binocle.Service
	config  def.Store

	def.ExpireStore
	*cache.Wrap

	models sync.Map
}

func NewEnvironment(context def.Context, service binocle.Service, store def.ExpireStore) *Environment {
	c := cache.Memory(context)

	env := &Environment{
		context: context,
		service: service,
		config:  c.Store(service.Name()),

		ExpireStore: store,
		Wrap:        cache.NewWrap(store),

		models: sync.Map{},
	}
	return env
}

func (env *Environment) ID() string {
	return env.service.Name()
}

func (env *Environment) Context() def.Context {
	return env.context
}

func (env *Environment) Transaction() (orm.Transaction, error) {
	return orm.DefaultExecutor().Begin()
}

func (env *Environment) SetConfig(key string, value interface{}) error {
	return env.config.Set(key, value)
}

func (env *Environment) Config(key string, value interface{}) error {
	return env.config.Get(key, value)
}

func (env *Environment) GetCache(openId string, key string, value interface{}) error {
	return env.Get(fmt.Sprintf(key+"/"+openId), value)
}

func (env *Environment) SetCache(openId string, key string, value interface{}, expire int) error {
	return env.SetExpire(fmt.Sprintf(key+"/"+openId), value, expire)
}

func (env *Environment) RegisterModel(name string, record interface{}) (*Table, error) {
	if _, ok := env.models.Load(name); ok {
		return nil, errors.New("[ Env ] Model " + name + " is exist!")
	}
	model := orm.NewModel(fmt.Sprintf("%s_"+name, env.id), record, nil)
	env.models.Store(name, model)
	table := &Table{Model: model}
	AddTableTo(table, env.id)
	return table, nil
}

func (env *Environment) GetModel(name string) (*orm.Model, error) {
	if m, ok := env.models.Load(name); ok {
		return m.(*orm.Model), nil
	}
	return nil, errors.New("[ Env ] Model " + name + " is not exist!")
}
